package com.itfreer.gis.datasyn;

import com.itfreer.file.path.FileUpload;
import com.itfreer.file.remote.download.FileDownloader;
import com.itfreer.file.remote.upload.FileUploader;
import com.itfreer.gis.datasyn.entity.ProjectEntity;
import com.itfreer.gis.datasyn.entity.SynLogEntity;
import com.itfreer.gis.datasyn.entity.TempProjectEntity;
import com.itfreer.gis.datasyn.sub.EditLogService;
import com.itfreer.gis.datasyn.sub.ProjectService;
import com.itfreer.gis.datasyn.sub.SynLogService;
import com.itfreer.utils.common.ZipperUtils;
import com.itfreer.utils.config.ConfigManager;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 数据编辑同步
 */
public class DataSynService {

    public static final DataSynService instance = new DataSynService();

    private DataSynService(){
    }

    /**
     * 数据同步
     */
    public void synData(final DataSynProgressListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if(ConfigManager.getConfig("DataUpload").equals(true)){
                        SynLogEntity log = update(listener);
                        if(log!=null){
                            download(listener);
                        }
                    } else {
                        download(listener);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 数据上传同步
     */
    private SynLogEntity update(final DataSynProgressListener listener) throws Exception {
        return update00(listener);
    }

    // 00:启动数据同步
    private SynLogEntity update00(final DataSynProgressListener listener) throws Exception {
        if(listener!=null){
            listener.onSize(4, 1, "启动数据同步");
        }

        SynLogEntity log = SynLogService.instance.addUpLog();
        if(log==null){
            if(listener!=null){
                listener.onFail("启动数据同步失败，请检查网络是否正常后重试！");
            }
            return null;
        }
        return update01(log, listener);
    }

    // 01:将需要上传的数据工程准备好，上传文件，上传工程信息
    private SynLogEntity update01(SynLogEntity log, final DataSynProgressListener listener) throws Exception{
        log = uploadLog(log, "01", "上传数据", 4, 2, listener);
        if(log==null){
            return null;
        }

        // 获取需要上传的对象
        List<ProjectEntity> needUploadProject = ProjectService.instance.getNeedUploadProject();
        if(needUploadProject == null || needUploadProject.size()<=0){
            EditLogService.instance.clearLogs();
            return uploadLog(log, "99", "无可上传数据，上传完成", 4, 4, listener);
        }

        for(ProjectEntity pro : needUploadProject) {
            // 压缩文件
            String path = pro.getPath();
            String[] paths = path.split(":");
            String buckt = paths[0];
            String key = paths[1];
            String fName = paths[2];
            fName = fName.replace(".zip", "").replace(".ZIP", "");
            String tempPath = FileUpload.instance.getDir(buckt, key) + "/" + fName + "/" + fName;

            // 压缩文件
            Collection<File> resFileList = new ArrayList<>();

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String ymd = sdf.format(new Date());
            String nFName = UUID.randomUUID().toString().replaceAll("-", "") + ".zip";
            key = ymd + "/";
            key += nFName;
            String zipDicPath = FileUpload.instance.getDir(buckt, key) + "/";
            File zipDicFile = new File(zipDicPath);
            if(!zipDicFile.isDirectory()){
                zipDicFile.mkdir();
            }
            String zipFilePath = zipDicPath + nFName;
            File zipFile = new File(zipFilePath);

            String dbfFilePath = tempPath + ".dbf";
            resFileList.add(new File(dbfFilePath));

            String fixFilePath = tempPath + ".fix";
            resFileList.add(new File(fixFilePath));

            String prjFilePath = tempPath + ".prj";
            resFileList.add(new File(prjFilePath));

            String shpFilePath = tempPath + ".shp";
            resFileList.add(new File(shpFilePath));

            String shxFilePath = tempPath + ".shx";
            resFileList.add(new File(shxFilePath));

            ZipperUtils.zipFiles(resFileList, zipFile);

            // 上传文件
            FileUploader uploader = new FileUploader(buckt, key);
            uploader.uploade();

            // 设置上传文件信息
            path = buckt + ":" + key + ":" + fName;
            pro.setPath(path);
        }

        // 上传工程信息，根据同步工程ID，记录工程信息
        if(ProjectService.instance.uploadSynProject(log.getId(), needUploadProject)){
            return update02(log, listener);
        } else {
            uploadLog(log, "01", "上传数据失败，请检查网络是否正常后重试", 4, 2, listener);
            return null;
        }
    }

    // 02:上传编辑记录信息
    private SynLogEntity update02(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "02", "上传编辑记录", 4, 3, listener);
        if(log==null){
            return null;
        }

        if(EditLogService.instance.uploadLog(log.getId())){
            return update03(log, listener);
        } else {
            uploadLog(log, "01", "上传编辑记录失败，请检查网络是否正常后重试", 4, 2, listener);
            return null;
        }
    }

    // 03:通知服务端更新数据，根据编辑记录，并等待服务端操作完成
    private SynLogEntity update03(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "03", "服务端数据同步", 4, 4, listener);
        if(log==null){
            return null;
        }

        if(ProjectService.instance.synUploadData(log.getId())){
            EditLogService.instance.clearLogs();
            return uploadLog(log, "99", "数据同步成功", 4, 4, listener);
        } else {
            uploadLog(log, "99", "数据同步失败，请检查网络是否正常后重试", 4, 4, listener);
            return null;
        }
    }

    /**
     * 数据下载同步
     */
    private void download(final DataSynProgressListener listener) throws Exception {
        download00(listener);
    }

    // 00:启动数据同步
    private SynLogEntity download00(final DataSynProgressListener listener) throws Exception {
        if(listener!=null){
            listener.onSize(9, 1, "启动数据同步");
        }

        SynLogEntity log = SynLogService.instance.addDownLog();
        if(log==null){
            if(listener!=null){
                listener.onFail("启动数据同步失败，请检查网络是否正常后重试！");
            }
            return null;
        }
        return download01(log, listener);
    }

    // 01:启动数据准备
    private SynLogEntity download01(SynLogEntity log, final DataSynProgressListener listener) throws Exception{
        log = uploadLog(log, "01", "启动数据准备", 9, 2, listener);
        if(log==null){
            return null;
        }

        // 通知服务端启动数据准备，并等待服务端准备好数据
        Boolean ready = ProjectService.instance.readySynData(log.getId());
        if(ready==null || ready==false){
            uploadLog(log, "01", "启动数据准备失败，请检查网络是否正常后重试！", 9, 2, listener);
            return null;
        }

        return download02(log, listener);
    }

    // 02:等待服务端数据准备好
    private SynLogEntity download02(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = SynLogService.instance.synLog(log.getId());
        if(log==null){
            if(listener!=null){
                listener.onFail("获取数据准备状态失败，请检查网络是否正常后重试！");
            }
            return null;
        }

        while (!log.getState().equals("02")){
            Thread.sleep(2000);
            log = SynLogService.instance.synLog(log.getId());
            if(log==null){
                if(listener!=null){
                    listener.onFail("获取数据准备状态失败，请检查网络是否正常后重试！");
                }
                return null;
            }else{
                if(listener!=null){
                    listener.onSize(9, 3, "数据准备中...");
                }
            }
        }
        return download03(log, listener);
    }

    // 03:同步Project工程同步表信息
    private SynLogEntity download03(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "03", "同步数据工程信息", 9, 4, listener);
        if(log==null){
            return null;
        }

        Boolean getProject = ProjectService.instance.getSynProject(log.getId());
        if(getProject==null || getProject==false){
            uploadLog(log, "03", "同步数据工程信息失败，请检查网络是否正常后重试！", 9, 4, listener);
            return null;
        }
        return download04(log, listener);
    }

    // 04:根据Project工程同步表，下载空间数据
    private SynLogEntity download04(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "04", "下载空间数据", 9, 5, listener);
        if(log==null){
            return null;
        }

        // 开始下载数据
        try{
            List<TempProjectEntity> projectEntities = ProjectService.instance.getLocalProject();
            if(projectEntities!=null){
                for(TempProjectEntity item : projectEntities){
                    // 数据为空间数据
                    String lType = item.getLayerType();
                    if (lType != null && (lType.trim().equals("01") || lType.trim().equals("02") || lType.trim().equals("03"))) {
                        // 数据同步类型为下载，或是双向同步
                        if (item.getSynType() != null
                                && (item.getSynType().trim().equals("01") || item.getSynType().trim().equals("02"))) {

                            String path = item.getPath();
                            String[] paths = path.split(":");
                            String buckt = paths[0];
                            String key = paths[1];

                            // 如果在，说明没有修改过
                            String file = FileUpload.instance.getFile(buckt, key);
                            File zipFile = new File(file);
                            if(!zipFile.exists()){
                                // 单线程，同步下载文件
                                FileDownloader downloader = new FileDownloader(buckt, key);
                                downloader.download();
                            }
                        }
                    }
                }
            }
        }catch (Exception e){
            uploadLog(log, "04", "下载空间数据失败，请检查网络是否正常后重试！", 9, 5, listener);
            return null;
        }
        return download05(log, listener);
    }

    // 05:解压空间文件
    private SynLogEntity download05(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "05", "解压空间数据", 9, 6, listener);
        if(log==null){
            return null;
        }

        // 解压文件
        try{
            List<TempProjectEntity> projectEntities = ProjectService.instance.getLocalProject();
            if(projectEntities!=null){
                for(TempProjectEntity item : projectEntities){
                    // 数据为空间数据
                    String lType = item.getLayerType();
                    if (lType != null && (lType.trim().equals("01") || lType.trim().equals("02") || lType.trim().equals("03"))) {
                        // 数据同步类型为下载，或是双向同步
                        if (item.getSynType() != null
                                && (item.getSynType().trim().equals("01") || item.getSynType().trim().equals("02"))) {

                            // plupload:20180815/o_1cku6jsqb93s13t5nl886nce4a.zip:JC_SLZY.zip
                            String path = item.getPath();
                            String[] paths = path.split(":");
                            String buckt = paths[0];
                            String key = paths[1];
                            String fName = paths[2];

                            String zipF = FileUpload.instance.getFile(buckt, key);
                            File zipFile = new File(zipF);

                            fName = fName.replace(".zip","").replace(".ZIP","");
                            String folderPath = FileUpload.instance.getDir(buckt, key) + "/" + fName;
                            ZipperUtils.upZipFile(zipFile, folderPath);
                        }
                    }
                }
            }
        }catch (Exception e){
            // 如果失败，就删除数据重新下载
            List<TempProjectEntity> projectEntities = ProjectService.instance.getLocalProject();
            if(projectEntities!=null){
                for(TempProjectEntity item : projectEntities){
                    // 数据为空间数据
                    String lType = item.getLayerType();
                    if (lType != null && (lType.trim().equals("01") || lType.trim().equals("02") || lType.trim().equals("03"))) {
                        // 数据同步类型为下载，或是双向同步
                        if (item.getSynType() != null
                                && (item.getSynType().trim().equals("01") || item.getSynType().trim().equals("02"))) {

                            // plupload:20180815/o_1cku6jsqb93s13t5nl886nce4a.zip:JC_SLZY.zip
                            String path = item.getPath();
                            String[] paths = path.split(":");
                            String buckt = paths[0];
                            String key = paths[1];
                            String fName = paths[2];

                            String zipF = FileUpload.instance.getFile(buckt, key);
                            File zipFile = new File(zipF);
                            zipFile.delete();
                        }
                    }
                }
            }

            uploadLog(log, "05", "解压空间数据失败，请重试！", 9, 6, listener);
            return null;
        }

        return download06(log, listener);
    }

    // 06:下载属性数据，目前存在风险
    private SynLogEntity download06(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "06", "下载属性数据", 9, 7, listener);
        if(log==null){
            return null;
        }

        return download07(log, listener);
    }

    // 07:更新移动端工程信息
    private SynLogEntity download07(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        log = uploadLog(log, "07", "更新移动端工程信息", 9, 8, listener);
        if(log==null){
            return null;
        }

        // 更新工程信息
        if(!ProjectService.instance.synProject()){
            uploadLog(log, "07", "更新移动端工程信息失败，请重试！", 9, 8, listener);
            if(listener!=null){
                listener.onFail("更新移动端工程信息失败，请重试！");
            }
            return null;
        }

        return download08(log, listener);
    }

    // 99:成功完成
    private SynLogEntity download08(SynLogEntity log, final DataSynProgressListener listener) throws Exception {
        EditLogService.instance.clearLogs();
        return uploadLog(log, "99", "数据同步成功", 9, 9, listener);
    }

    /**
     * 更新日志
     * @param log
     * @param state
     * @param msg
     * @return
     */
    private SynLogEntity uploadLog(SynLogEntity log, String state, String msg,
                                   int count, int size,
                                   final DataSynProgressListener listener){
        log.setState(state);
        log.setReport(log.getReport() + msg + "\n");
        log = SynLogService.instance.updateLog(log);
        if(log == null){
            if(listener!=null){
                listener.onFail("更新状态失败，请检查网络是否正常后重试！");
            }
            return null;
        }else{
            if(listener!=null){
                listener.onSize(count, size, msg);
            }
            return log;
        }
    }
}
